function getCanvasContext(id) {
    var canvas = document.getElementById(id);
    return canvas.getContext('2d');    
}

// ---------------- Begin 'Base Class' Star --------------------

function Star(){
    this.pos=[];
    this.origin=[];
    this.velocity=0;     
    this.phi=0; // angle 
    this.age=0; // age in seconds
    this.isHidden = false;
}

Star.prototype.render = function(context, elapsed){
    var d = elapsed === 0 ? d : elapsed * this.velocity * (this.age*this.age);
    
    if(this.isHidden){
        this.reset();
        this.isHidden=false;
    }
    this.age += elapsed;
    this.draw(context, d);
};

Star.prototype.draw = function(context, d) { console.log("draw: Not implemented");  };

Star.prototype.reset = function(context) { console.log("draw: Not implemented"); };

// ---------------- End Star --------------------
                                 
// ---------------- Begin Pixel Star --------------------
PixelStar.prototype = new Star();

function PixelStar() 
{
    this.pixel = getCanvasContext('fg').createImageData(1,1);
    this.pixel.data[0] = 255;
    this.pixel.data[1] = 255;
    this.pixel.data[2] = 255;
    this.pixel.data[3] = 0;
    
}

PixelStar.prototype.draw = function(context, d){

    this.pos[0] = this.pos[0] + (d * Math.cos(this.phi) );    
    this.pos[1] = this.pos[1] + (d * Math.sin(this.phi) );    

    this.pixel.data[3] = (this.age/3)*255;
    context.putImageData( this.pixel, this.pos[0], this.pos[1] );    
};

PixelStar.prototype.reset = function(){

    this.age = 0;
    this.pos = this.origin.slice();
    this.phi = Math.random() * 2 * Math.PI;
    this.velocity = (Math.random() * 20)+5;

    
    this.pixel.data[0]= 255;
    this.pixel.data[1]= 255;
    this.pixel.data[2]= 255;
    this.pixel.data[3]= 0;    
};

// ---------------- End Pixel Star --------------------

// ---------------- Begin Sprite Star --------------------
SpriteStar.prototype = new Star();

function SpriteStar(sprite) 
{
    this.sprite = sprite;
    this.rotationSpeed = 0;
    this.scaleSpeed = 0.0;
}

SpriteStar.prototype.draw = function(context, d){

    this.pos[0] = this.pos[0] + (d * Math.cos(this.phi) );    
    this.pos[1] = this.pos[1] + (d * Math.sin(this.phi) );    
    var tx = this.pos[0]+10;
    var ty = this.pos[1]+10;
        
    
    context.save();    
    context.translate(tx, ty);
    if(this.scaleSpeed>0.01){
        var scale = this.age*this.scaleSpeed;
        context.scale(scale,scale);
    }
    if(this.rotationSpeed>0.01){
        context.rotate((this.age * this.rotationSpeed)/100);
    }
    context.translate(-tx, -ty);
    context.drawImage(this.sprite, this.pos[0], this.pos[1]);    
    context.restore();
};

SpriteStar.prototype.reset = function(){
    
    this.age = 0;
    this.pos = this.origin.slice();
    this.phi = Math.random() * 2 * Math.PI;
    this.velocity = (Math.random() * 20)+5;

    this.rotationSpeed = Math.random() * 100;
    this.scaleSpeed = Math.random();
};
// ---------------- End Pixel Star --------------------

function Stats(){
    var font = "12px Arial";
    var fps = 0;
    var age = 0;
    this.render = function(context, elapsed, numberOfStars){
        fps++;        
        age += elapsed;
        if(age>1.0){
            context.clearRect(0,0,120,32);
            context.fillStyle = "white";
            context.font = font;
            context.textAlign = "left";
            context.fillText(numberOfStars + ' Stars - FPS:' + fps, 10, 20);
            fps=0;
            age=0;
        }
    };
}


function Starfield(noStars, showStats){
    var fgContext = getCanvasContext('fg');
    var bgContext = getCanvasContext('bg');
    var statsContext = getCanvasContext('stats');
    var stars = [];
    var lastUpdate = 0;
    var elapsed = 0;
    var overallElapsed=0;
    var stats = null;    
    var numberOfStars = noStars;    
    var imageBuffer = [];
    var spriteBuffer = [];    
    var center = [0,0];
    var bitmapsToLoad = [
            {type: "image", src: './img/space_background.1024x768.jpg' },
            {type: "sprite", src: './img/star.png' },
            {type: "sprite", src: './img/star2.png' }
        ];
    
    
    
    var update = function(){       
        fgContext.clearRect(-100,-100, fgContext.canvas.width+100, fgContext.canvas.height+100);
        var now = new Date().getTime();
        elapsed = (now - lastUpdate)/1000;   // seconds  
        overallElapsed += elapsed;
        fgContext.save();
        fgContext.translate( center[0], center[1]);
        fgContext.rotate(overallElapsed * 0.5); 
        fgContext.translate( -center[0], -center[1]);
        for(var i=0;i<stars.length;++i){            
            stars[i].isHidden = isHidden(stars[i].pos);
            stars[i].render(fgContext, elapsed);                 
        }             
        fgContext.restore();
        lastUpdate=now;
        if(stats!==null){ 
            stats.render(statsContext, elapsed, stars.length); 
        }
        requestAnimationFrame(update);
    };
    
    var isHidden = function(pos){
        return ( pos[0]<-100 || pos[0]>fgContext.canvas.width+100 ) || 
            ( pos[1]<-100 || pos[1]>fgContext.canvas.height+100 );
    };
    
    var render = function(){        
        lastUpdate = new Date().getTime();  
        requestAnimationFrame(update);    
    };
    
    var loadBitmapBuffer = function(bitmaps){                
        
        for(var i=0; i<bitmaps.length; ++i){            
            var imgObj = new Image();
            imgObj.onload = onImageLoaded;
            imgObj['bitmapType'] = bitmaps[i].type;            
            imgObj.src = bitmaps[i].src;
        }
    };
    
    var onImageLoaded = function(e){
        var img = e.target;
        if(img.bitmapType === 'image'){
            imageBuffer.push(img);
        }
        else if(img.bitmapType === 'sprite'){
            spriteBuffer.push(img);
        }
        
        var numberLoadedImages = imageBuffer.length + spriteBuffer.length;
        if(numberLoadedImages  === bitmapsToLoad.length){
            onAllBitmapsLoaded();
        }
    }; 
    
    var onAllBitmapsLoaded = function(){
        bgContext.drawImage(imageBuffer[0],0,0);            
        initStars();   
        render();
    };
    
    var initStars = function(){
        
        // pixel stars
        var nPixelStars = (numberOfStars*0.9)<<0;
        var i=0;
        for(i=0; i<nPixelStars; ++i){            
            addStar( new PixelStar() );            
        }             
        
        // sprite stars - put on behind to be drawn over the pixelstars
        var nSpriteStars = numberOfStars-nPixelStars;
        for(i=0; i<nSpriteStars; ++i)
        {
            var index = Math.round(Math.random() * (spriteBuffer.length-1));
            addStar( new SpriteStar(spriteBuffer[index<<0]) );                            
        }
    };

    var addStar = function(star){
        star.origin = [center[0], center[1]];
        star.reset();
        stars.push( star );
    };
    
    var removeStar = function(){
        stars.pop();
    };
    
    var onKeyPress = function(e){
        if(e.keyCode==43){ // '+'
            var index = Math.round(Math.random() * (spriteBuffer.length-1))<<0;            
            addStar(stars.length % 10 === 0 ? new SpriteStar(spriteBuffer[index]) : new PixelStar());
        }
        else if (e.keyCode==45){ // '-'
            removeStar();
        }
    };
    
    var initialize = function(numberOfstars, showStats){        

        var canvas= document.getElementById('fg');
        center[0] = canvas.width/2;
        center[1] = canvas.height/2;
        
        window.addEventListener("keypress", onKeyPress, false);
        
        if(showStats){
            stats = new Stats();            
        }
            
        loadBitmapBuffer(bitmapsToLoad, onAllBitmapsLoaded);

    };
    
    
        
    initialize(numberOfStars, showStats);
}




